package it.softphone.commons.util;


import it.softphone.commons.exception.NullParameterException;
import it.softphone.commons.service.LogAware;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Locale;
import java.util.jar.Manifest;
import java.util.regex.Matcher;


import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberType;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;

/**
 * commons util functions
 * 
 * @author softphone
 *
 */
public class Util implements LogAware {

	private static java.util.regex.Pattern varPattern = java.util.regex.Pattern.compile("\\$\\{(\\w+[\\.]?\\w+)\\}");
	
	/**
	 * 
	 * @param input
	 * @param parameters
	 * @return
	 */
	public static String variableSubstitution( String input, java.util.Map<String,String> parameters ) {

		Matcher m = varPattern.matcher(input);
		
		StringBuffer sb = new StringBuffer();
    	int index = 0;
    	while( m.find() ) {
    		
    		logger.debug( "try to resolve var " + m.group(1) );
    		
    		sb.append( input.substring(index, m.start() ) );
    		if( parameters.containsKey(m.group(1)))
    			sb.append( parameters.get( m.group(1) ) );
    		else 
    			sb.append( System.getProperty( m.group(1), m.group(0) ) );
    			
    		index = m.end();

    		
    	}
    	
    	return (index==0) ? input : sb.append( input.substring(index) ).toString();
	}

	
	/**
	 *  
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static String toString( java.io.File file ) throws FileNotFoundException, IOException {
		if( file == null ) throw new NullParameterException("file");
		if( file.isDirectory() ) throw new IllegalArgumentException("file " + file + " is a directory");

		return toString( new java.io.FileReader(file));
	}

	/**
	 *  
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static String toString( java.io.Reader reader ) throws IOException {
		if( reader == null ) throw new NullParameterException("reader");

		java.io.Reader r = null;
		
		if( reader instanceof java.io.BufferedReader ) {
			r = reader;
		}
		else {
		
			r = new java.io.BufferedReader(reader);
		}
		
		StringBuilder contents = new StringBuilder(4096);
		
		int c;
		while(  (c = r.read())!=-1 ) {

			contents.append( (char)c );
		}

		return contents.toString();

	}
	
	/**
	 * 
	 * @param reader
	 * @param bufferSizeInKBytes
	 * @return
	 * @throws IOException
	 */
	public static byte[] toBytes( java.io.InputStream reader, int bufferSizeInKBytes ) throws IOException {
		if( reader == null ) throw new NullParameterException("reader");

		java.io.InputStream r = null;
		
		if( reader instanceof java.io.BufferedInputStream ) {
			r = reader;
		}
		else {
		
			r = new java.io.BufferedInputStream(reader,bufferSizeInKBytes * 1024);
		}
		
		java.io.ByteArrayOutputStream contents = new java.io.ByteArrayOutputStream(bufferSizeInKBytes * 1024);
		
		int c;
		while(  (c = r.read())!=-1 ) {

			contents.write(c);
		}

		return contents.toByteArray();

	}
	
	/**
	 *  
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static byte[] toBytes( java.io.File file, int bufferSizeInKBytes ) throws FileNotFoundException, IOException {
		if( file == null ) throw new NullParameterException("file");
		if( file.isDirectory() ) throw new IllegalArgumentException("file " + file + " is a directory");

		return toBytes( new java.io.FileInputStream(file), bufferSizeInKBytes);
	}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	
//
// VALIDATORS
//	
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	public static final String EMAIL_PATTERN_STRING = 
            "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

	public static final java.util.regex.Pattern EMAIL_PATTERN = java.util.regex.Pattern.compile(EMAIL_PATTERN_STRING);

	/**
	 * 
	 * @param hex
	 * @return
	 * 
	 * {@link}http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/
	 */
	public static boolean isValidMail( final String hex ) {
		if( null==hex ) return false;
		java.util.regex.Matcher matcher = EMAIL_PATTERN.matcher(hex);
		
		return matcher.matches();
		
	}
	
	/**
	 * 
	 * @param hex
	 * @return
	 */
	public static boolean isValidPhone( final String hex, Locale defaultLocale ) {
		
		if( null == hex ) return false;
		
		PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
		
		try {
			
			PhoneNumber n = phoneUtil.parse(hex, defaultLocale.getCountry());

			return ( n!=null && phoneUtil.isValidNumber(n));
			
		}
		catch( NumberParseException ex ) {
			logger.warn( String.format( "error parsing phone number [%s]", hex), ex);
		}
		
		return false;
	
	}
	
	/**
	 * 
	 * @param hex
	 * @return
	 * 
	 * {@link}
	 */
	public static boolean isValidMobilePhone( final String hex, Locale defaultLocale ) {
		
		if( null == hex ) return false;
		
		PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
		
		try {
			
			PhoneNumber n = phoneUtil.parse(hex, defaultLocale.getCountry());

			return ( n!=null && phoneUtil.isValidNumber(n) && phoneUtil.getNumberType(n)==PhoneNumberType.MOBILE);
			
		}
		catch( NumberParseException ex ) {
			logger.warn( String.format( "error parsing phone number [%s]", hex), ex);
		}
		
		return false;
	}

	/**
	 * 
	 * @author softphone
	 *
	 */
	public interface ManifestPredicate {
		
		/**
		 * 
		 * @param mf
		 * @return true to continue scan othewise false
		 */
		boolean evaluate( java.util.jar.Manifest mf, java.net.URL url ); 
	}
	
	/**
	 * 
	 * @param classloader
	 * @param predicate
	 * @throws IOException
	 */
	public static void forEachManifest( ClassLoader classloader, ManifestPredicate predicate ) throws IOException {
		if( predicate == null ) throw new NullParameterException("predicate");
		if( classloader == null ) throw new NullParameterException("classloader");
		
		java.util.Enumeration<java.net.URL> resources = classloader.getResources("META-INF/MANIFEST.MF");
		while (resources.hasMoreElements()) {
			final java.net.URL url = resources.nextElement();
			
		    try {
		    	java.util.jar.Manifest manifest = new java.util.jar.Manifest(url.openStream());

		    	if( !predicate.evaluate(manifest, url) ) break;
		    			    	
		    	
		    } catch (IOException E) {
		      logger.warn( String.format("error reading manifest [%s]", url ), E);
		    }
		}
	}
	
}
